#pragma once

#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <type_traits>
#include <vector>

#if !defined(M_PI)
#define M_PI 3.14159265358979323846
#endif

#include "types.hpp"

namespace ly {

template <class C>
struct vec2 {
 private:
  C m_x, m_y;

 public:
  vec2() : m_x(0), m_y(0) {}

  vec2(C x, C y) : m_x(x), m_y(y) {}

  template <class D>
  vec2(D x, D y) : m_x((C)llround(x)), m_y((C)llround(y)) {}

  vec2(const vec2<C>& d) : m_x(d.m_x), m_y(d.m_y) {}

  /**
   * @brief 获取x坐标值
   * @return x坐标值
   */
  C x() const { return m_x; }

  /**
   * @brief 获取y坐标值
   * @return y坐标值
   */
  C y() const { return m_y; }

  /**
   * @brief 设置x坐标值
   * @param x x坐标值
   */
  void x(C x) { m_x = x; }

  /**
   * @brief 设置y坐标值
   * @param y y坐标值
   */
  void y(C y) { m_y = y; }

  template <class T>
  vec2<C>& operator*=(T s) {
    m_x = (C)llround(m_x * s);
    m_y = (C)llround(m_y * s);
    return *this;
  };

  template <class T>
  vec2<C>& operator/=(T s) {
    double mult = 1.0 / static_cast<double>(s);
    *this *= mult;
    return *this;
  };
};
// 非成员运算符重载
template <class C>
inline vec2<double> operator*(const vec2<C>& p, double s) {
  return vec2<double>(p.x() * s, p.y() * s);
}

template <class C, class T>
inline std::enable_if_t<std::is_integral_v<T>, vec2<C>> operator*(const vec2<C>& p, T s) {
  return vec2<C>(p.x() * s, p.y() * s);
}

template <class C, typename N>
inline vec2<C> operator/(const vec2<C>& p, N s) {
  double mult = 1.0 / static_cast<double>(s);
  return vec2<C>(p.x() * mult, p.y() * mult);
}
// 定义模板别名：point<T> 等价于 vec2<T>
template <class C>
using point = vec2<C>;

// // 定义点类型
typedef vec2<Coord> Point;
typedef std::vector<vec2<Coord>> PointVec;
typedef std::vector<vec2<Coord>> Points;

typedef vec2<DCoord> DPoint;
typedef std::vector<vec2<DCoord>> DPointVec;

}  // namespace ly
